package uem

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

func Debug(formating string, args ...interface{}) {
	outlog("DEBUG", formating, args...)
}
func Warning(formating string, args ...interface{}) {
	outlog("WARNING", formating, args...)
}
func Info(formating string, args ...interface{}) {
	outlog("INFO", formating, args...)
}
func Error(formating string, args ...interface{}) {
	outlog("ERROR", formating, args...)
}

func outlog(level string, formating string, args ...interface{}) {
	filename, line, funcname := "???", 0, "???"

	pc, filename, line, ok := runtime.Caller(2)
	if ok {
		funcname = runtime.FuncForPC(pc).Name()      // main.(*MyStruct).foo
		funcname = filepath.Ext(funcname)            // .foo
		funcname = strings.TrimPrefix(funcname, ".") // foo
		filename = filepath.Base(filename)           // /full/path/basename.go => basename.go
	}

	log := fmt.Sprintf("%s: [filename: %s] [line:%d] [function:%s]=>  {%s}  \n", level, filename, line, funcname, fmt.Sprintf(formating, args...))

	switch level {
	case "ERROR":
		fmt.Fprintf(os.Stderr, Red(log))
	case "INFO":
		fmt.Fprintf(os.Stderr, Green(log))
	case "WARNING":
		fmt.Fprintf(os.Stderr, Blue(log))
	case "DEBUG":
		fmt.Fprintf(os.Stderr, Green(log))
	default:
		fmt.Fprintf(os.Stderr, Red(log))
	}
}

type Logger struct {
	f     *os.File
	o     *log.Logger
	debug bool
}

func NewLog(path string, debug bool) (*Logger, error) {

	l := &Logger{}
	l.debug = debug

	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalln("Failed to open error log file:", err)
		return nil, err
	}

	l.f = file
	l.o = log.New(io.MultiWriter(file, os.Stderr), "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)

	return l, nil
}

func (l *Logger) Getfile() *os.File {
	return l.f
}

func (l *Logger) Close() {
	l.f.Close()
}

func (l *Logger) SetMode(debug bool) {

	l.debug = debug
}

func (l *Logger) getlogsize() {

	fileInfo, err := l.f.Stat()
	if err != nil {
		log.Fatal(err)
	}

	size := float64(fileInfo.Size()) / (1024 * 1024)
	if size > 1 {

	}
}

func (l *Logger) Debug(formating string, args ...interface{}) {

	if l.debug == true {
		outlog("DEBUG", formating, args...)
	} else {
		l.log("DEBUG", formating, args...)
	}
}

func (l *Logger) Warning(formating string, args ...interface{}) {
	if l.debug == true {
		outlog("WARNING", formating, args...)
	} else {
		l.log("WARNING", formating, args...)
	}
}

func (l *Logger) Info(formating string, args ...interface{}) {
	if l.debug == true {
		outlog("INFO", formating, args...)
	} else {
		l.log("INFO", formating, args...)
	}
}

func (l *Logger) Error(formating string, args ...interface{}) {
	if l.debug == true {
		outlog("ERROR", formating, args...)
	} else {
		l.log("ERROR", formating, args...)
	}
}

func (l *Logger) log(level string, formating string, args ...interface{}) {
	filename, line, funcname := "???", 0, "???"

	pc, filename, line, ok := runtime.Caller(2)
	if ok {
		funcname = runtime.FuncForPC(pc).Name()      // main.(*MyStruct).foo
		funcname = filepath.Ext(funcname)            // .foo
		funcname = strings.TrimPrefix(funcname, ".") // foo
		filename = filepath.Base(filename)           // /full/path/basename.go => basename.go
	}

	log := fmt.Sprintf("[%s][filename: %s] [line:%d] [function:%s]=>  {%s}  \n", level, filename, line, funcname, fmt.Sprintf(formating, args...))

	switch level {
	case "ERROR":
		fmt.Fprintf(l.f, log)
	case "INFO":
		fmt.Fprintf(l.f, log)
	case "WARNING":
		fmt.Fprintf(l.f, log)
	case "DEBUG":
		fmt.Fprintf(l.f, log)
	default:
		fmt.Fprintf(l.f, log)
	}
}
